package main

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

func main() {
	r := gin.Default()

	// 定义路由组 v1，不需要 JWT 认证
	v1 := r.Group("/v1")
	{
		v1.GET("/hqtoken", Hqtoken) // 获取 JWT 令牌的接口
	}

	// 定义路由组 v2，使用 JWT 认证中间件
	v2 := r.Group("/v2", Jwtyz())
	{
		v2.GET("/yztoken", Yztoken) // 需要 JWT 认证的接口
	}

	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

// Hqtoken 生成 JWT 令牌并返回
func Hqtoken(c *gin.Context) {
	// 定义 JWT 签名密钥
	mySigningKey := []byte("Xye8pxrmruM")

	// 定义自定义声明结构体
	type MyCustomClaims struct {
		Userid string `json:"userid"` // 用户 ID
		jwt.RegisteredClaims         // 继承标准 JWT 声明
	}

	// 设置用户 ID
	userid := "144551222554"

	// 创建 JWT 声明
	claims := MyCustomClaims{
		Userid: userid,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 令牌 24 小时后过期
			Issuer:    "alsark", // 签发者
		},
	}

	// 使用 HS256 签名算法创建 JWT 令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 使用密钥对令牌进行签名
	ss, _ := token.SignedString(mySigningKey)

	// 输出 JWT 令牌到终端
	fmt.Println(ss)

	// 返回 JWT 令牌给客户端
	c.JSON(200, ss)
}

// Yztoken 需要 JWT 认证的接口
func Yztoken(c *gin.Context) {
	// 获取中间件存储的用户 ID
	userid, _ := c.Get("userid")

	// 打印用户 ID
	fmt.Println(userid)
}

// Jwtyz JWT 认证中间件
func Jwtyz() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头中获取 Authorization 字段
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" {
			// 若请求头中无 Authorization，则返回 401
			c.JSON(401, gin.H{"error": "Authorization异常"})
			c.Abort()
			return
		}

		// 定义自定义声明结构体
		type MyCustomClaims struct {
			Userid string `json:"userid"` // 用户 ID
			jwt.RegisteredClaims         // 继承标准 JWT 声明
		}

		// 解析 JWT 令牌，并验证签名
		token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
			// 返回用于签名的密钥
			return []byte("Xye8pxrmruM"), nil
		})

		// 检查解析是否出错
		if err != nil {
			c.JSON(401, gin.H{"error": "Authorization异常"})
			c.Abort()
			return
		} else if claims, ok := token.Claims.(*MyCustomClaims); ok {
			// 成功解析并断言为 MyCustomClaims 结构体，将用户 ID 存入上下文
			c.Set("userid", claims.Userid)
		} else {
			// 解析失败，未知的声明类型
			c.JSON(401, gin.H{"error": "Authorization异常"})
			c.Abort()
			return
		}

		// 继续处理请求
		c.Next()
	}
}
